package modelo.controlAereo;

import modelo.Escenografia.Escenario;
import java.util.ArrayList;
import java.util.Iterator;
import modelo.Escenografia.Pista;
import modelo.Orientacion.Posicion;

public class TorreDeControl {

	private ArrayList<Aeronave> aeronaves;
        private ArrayList<Aeronave> aeronavesAterrizadas;
	private ArrayList<Aeronave> aeronavesChocadas;
        private boolean chocoAlgunaAeronave;
	private int cantidadDeAvionesAterrizados;
	
	//Se crea una instancia de TorreDeControl con la lista de aviones vac�a y con el contador de aviones aterrizados en 0
	//Pre: -
	//Pos: Se crea una instancia de TorreDeControl.
	public TorreDeControl(){
		this.aeronaves = new ArrayList<Aeronave>();
		this.aeronavesChocadas = new ArrayList<Aeronave>();
                this.aeronavesAterrizadas = new ArrayList<Aeronave>();
		this.cantidadDeAvionesAterrizados =0;
                this.chocoAlgunaAeronave = false;
	}

	//Se agrega una nueva aeronave a la lista de aeronaves
	//Precondici�n: Se debe haber creado una instancia de TorreDeControl
	//Poscondici�n: Aumenta la cantidad de elementos del atributo de instancia 'aeronaves'
	public void agregarAeronave(Aeronave unaAeronave) {
		aeronaves.add(unaAeronave);
                this.comprobarChoques();    //Esto se hace por si agregamos una aeronave en la misma posicion de otro avion
	}
	
	//Se agrega la posici�n final de una nueva trayectoria a un avion posicionado en 'unaPosicion'
	//Precondici�n1: Se debe haber creado una instancia de TorreDeControl.
	//Precondici�n2: 'unaTrayectoria' debe ser una posici�n previamente validada que se encuentre dentro del rango de posiciones posibles para realizar un movimiento
	//Poscondici�n: -
	public void agregarTrayectoriaAAeronaveEnPosicion(Posicion unaPosicion,Posicion unaTrayectoria)
	{
		Aeronave unaAeronave = obtenerAvionSegunPosicion(unaPosicion);
		if (unaAeronave != null) 
		{
			unaAeronave.agregarTrayectoria(unaTrayectoria);
		}

	}

	//Le env�a el mensaje 'mover' a cada aeronave. Luego de esto, comprueba los choques.
	//Precondici�n: Se debe haber creado una instancia de TorreDeControl y el escenario debe tener por lo menos una pista
	//Poscondici�n: Las aeronaves cambian su posici�n.
	public void avanzarAviones(Escenario escenario) {
		Iterator<Aeronave> iteradorAeronaves = this.aeronaves.iterator();
		Aeronave unaAeronave;
		while((aeronaves.size()>0)&& (iteradorAeronaves.hasNext())){
			unaAeronave = iteradorAeronaves.next();
			unaAeronave.mover();
                        if (!escenario.verificarPosicion(unaAeronave.obtenerPosicion())){
                            unaAeronave.chocarConLosLimites();
                            unaAeronave.mover();
                        }
                } //Primero muevo todo y luego controlo
                this.chequearAterrizajesEn(escenario.obtenerPistas());
                this.comprobarChoques();
	}

        public boolean algunAvionChoco(){
        /*PreCondicion: la torre de control debe estar creada
          PostCondicion: devuelve true si algun avion choco, en caso contrario devuelve false*/
            return this.chocoAlgunaAeronave;
        }

	//Comprueba si las aeronaves pueden realizar aterrizaje en alguna de las pistas de 'listaDePistas'
	//Precondici�n: Se debe haber creado una instancia de TorreDeControl y la listaDePistas no puede estar vacia
	//Poscondici�n: En caso que una aeronave pueda aterrizar, cambia su estado a aterrizado
    	private void chequearAterrizajesEn(ArrayList<Pista> listaDePistas){
            Iterator<Aeronave> iteradorAeronaves = aeronaves.iterator();

            boolean aterrizo = false;
            while (iteradorAeronaves.hasNext()){  
                aterrizo = false;
    			Aeronave unaAeronave = iteradorAeronaves.next();
    			Iterator<Pista> iteradorPistas = listaDePistas.iterator();
    			while (iteradorPistas.hasNext() && !aterrizo ){
    	    		Pista unaPista = iteradorPistas.next();
    			if( (unaAeronave.puedeAterrizarEn(unaPista)) && (unaPista.estaEnLaPista(unaAeronave)) ){
    				this.cantidadDeAvionesAterrizados++;
                                aeronavesAterrizadas.add(unaAeronave);
    				iteradorAeronaves.remove();
    		                aterrizo = true;       
    			}
                }

            }
    	}
	
	//Comprueba si alguna de las aeronaves choca con alguna otra.
	//Precondici�n: Se debe haber creado una instancia de TorreDeControl
	//Poscondici�n: En caso que una aeronave pueda chocar, cambia su estado a chocado y es eliminado de la lista de aeronaves y agregado a la ista de aeronaves chocados
	private void comprobarChoques() {
            boolean  aeronaveChoco = false;
            int i = 0;
            while (i < aeronaves.size() && aeronaveChoco == false ) {
                Aeronave unaAeronave = aeronaves.get(i) ;
                aeronaveChoco = false;
                int j= 0;
    		while (j < aeronaves.size() && aeronaveChoco == false ) {
                    if (i != j){
                        Aeronave otraAeronave = aeronaves.get(j) ;
                        aeronaveChoco = aeronaveChoco || unaAeronave.chocaConMovible(otraAeronave);
                    }
                    if (aeronaveChoco){
                        aeronavesChocadas.add(unaAeronave);
                        aeronavesChocadas.add(aeronaves.get(j));
                        aeronaves.remove(j);
                        aeronaves.remove(i);
                     }else{
                        j++;                    	
                    }
                }
                if (!aeronaveChoco)	i++;
            }
            this.chocoAlgunaAeronave = this.chocoAlgunaAeronave || aeronaveChoco;
	}
	
	//Precondici�n: Se debe haber creado una instancia de TorreDeControl
	//Poscondici�n: -
	public int devolverCantidadDeAvionesAterrizados(){
		return this.cantidadDeAvionesAterrizados;
	}

	public ArrayList<Aeronave> obtenerAviones() {
		return aeronaves;
	}

	//Se obtiene una aeronave que se encuentre en la posicion 'unaPosicion'
	//Precondici�n: Se debe haber creado una instancia de TorreDeControl
	//Poscondici�n1: Si se encuentra la aeronave, se devuelve la instancia.
	//Poscondici�n2: Si no se encuentra la aeronave, se devuelve 'null'.
	public Aeronave obtenerAvionSegunPosicion(Posicion unaPosicion) {
		Iterator<Aeronave> iteradorAeronaves = this.aeronaves.iterator();
		Aeronave unaAeronave;
		while (iteradorAeronaves.hasNext()){
			unaAeronave = iteradorAeronaves.next();
			if (unaPosicion == unaAeronave.obtenerPosicion() ){
				return unaAeronave;
			}	
		}
		return null;
	}
	
	public void eliminarAeronavesChocadas(){
        /*PreCondicion: la torre de control debe estar creada
          PostCondicion: elimina las aeronaves chocadas de la torre*/
		aeronavesChocadas.clear();
	}
	
	public ArrayList<Aeronave> devolverAeronavesChocadas(){
        /*PreCondicion: la torre de control debe estar creada
          PostCondicion: devuelve una lista con las aeronaves chocadas*/
		return this.aeronavesChocadas;
	}

        public ArrayList<Aeronave> devolverAeronavesAterrizadas(){
        /*PreCondicion: la torre de control debe estar creada
          PostCondicion: devuelve una lista con las aeronaves chocadas*/
		return this.aeronavesAterrizadas;
	}

        public void eliminarAeronavesAterrizadas(){
        /*PreCondicion: la torre de control debe estar creada
          PostCondicion: elimina las aeronaves chocadas de la torre*/
		aeronavesAterrizadas.clear();
	}

}
